/**
 * LeafSetTest.java
 * ************************** 
 * @date Apr 27, 2011
 * @author Michele Tamburini
 * 
 * **************************
 */
package JUnitTests;

import static org.junit.Assert.*;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.Vector;

import gossipServices.basic.nodeDescriptors.ConcreteNodeDescriptor;
import gossipServices.basic.nodeDescriptors.GeneralNodeDescriptor;
import gossipServices.basic.nodeDescriptors.NodeDescriptor;
import gossipServices.bootstraping.theBootstrapingService.ConcreteLeafSet;
import gossipServices.bootstraping.theBootstrapingService.LeafSet;

import org.junit.Before;
import org.junit.Test;

/**
 * Description: 
 *
 */
public class LeafSetTest {
	
	static final int LEAFSET_SIZE = 15;
	String names[] = {"node1", "node2", "node3", "node4", "node5", "node6", "pippo"};
	String localName = "inTheMiddle";
	LeafSet leafSet;
	Vector<NodeDescriptor> initialVec;
	NodeDescriptor localNodeDescriptor;

	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		initialVec = new Vector<NodeDescriptor>();
		for(int i=0; i<names.length; i++){
			initialVec.add(new ConcreteNodeDescriptor(names[i]));
		}
		localNodeDescriptor = new ConcreteNodeDescriptor(localName);
		leafSet = new ConcreteLeafSet(LEAFSET_SIZE, initialVec,
				localNodeDescriptor);
	}

	/**
	 * Test method for {@link gossipServices.bootstraping.theBootstrapingService.ConcreteLeafSet#ConcreteLeafSet(int, java.util.List)}.
	 */
	@Test
	public void testConcreteLeafSet() {
		assertNotNull(leafSet);
		assertTrue(leafSet.size() == LEAFSET_SIZE);
//		fail("Not yet implemented");
	}

	/**
	 * Test method for {@link gossipServices.bootstraping.theBootstrapingService.ConcreteLeafSet#head(int)}.
	 */
	@Test
	public void testHead() {
		int firstElements = 3;
		LeafSet subset = leafSet.head(firstElements);
		assertEquals(subset.size(), firstElements);
		for(int i=0; i<firstElements; i++){
			assertEquals(subset.get(i), leafSet.get(i));
		}
//		fail("Not yet implemented");
	}

	/**
	 * Test method for {@link gossipServices.bootstraping.theBootstrapingService.ConcreteLeafSet#selectPeer()}.
	 */
	@Test
	public void testSelectPeer() {
		LeafSet sameLeafSet = new ConcreteLeafSet(LEAFSET_SIZE, initialVec, localNodeDescriptor);
		int selected = 3;
		NodeDescriptor nodes[] = new NodeDescriptor[selected];
		boolean found[] = new boolean[selected];
		for(int i=0; i< selected; i++){
			nodes[i] = leafSet.selectPeer();
			found[i] = false;
		}
		sameLeafSet.sort();
		LeafSet firstHalf = sameLeafSet.head(sameLeafSet.size()/2);
		for(int i=0; i<selected; i++){
			for(int j=0; j<firstHalf.size(); j++){
				if(firstHalf.get(j).equals(nodes[i]))
					found[i] = true;
			}
		}
		for(boolean f : found)
			assertTrue(f);
//		fail("Not yet implemented");
	}

	/**
	 * Test method for {@link gossipServices.bootstraping.theBootstrapingService.ConcreteLeafSet#size()}.
	 */
	@Test
	public void testSize() {
		assertEquals(leafSet.size(), LEAFSET_SIZE);
//		fail("Not yet implemented");
	}


	/**
	 * Test method for {@link gossipServices.bootstraping.theBootstrapingService.ConcreteLeafSet#sort()}.
	 */
	@Test
	public void testSort() {
		leafSet.sort();
		int prec = 0;
		for(int i =1 ; i<leafSet.size(); i++){
			// Some nodes may have the same value and in that case they are 
			// EMPTY nodes.
			assertTrue(leafSet.get(prec).getNodeID() <= leafSet.get(i).getNodeID());
			prec = i;
		}
//		fail("Not yet implemented");
	}
	
	@Test
	public void testAdjustSuccPrec(){
		/*
		 * The adjust has to keep the size of the leafSet at the 
		 * fixed value.
		 */
		int nprec =0, nsucc=0;
		boolean found = false;
		print("TestAdjustSuccPrecc\nBefore:");
		String names2[] = {"firstAdd", "secondAdd", "thirdAdd", "fourthAdd"};		
		Deque<NodeDescriptor> adding = new ArrayDeque<NodeDescriptor>(names2.length);
		Vector<NodeDescriptor> total = (Vector<NodeDescriptor>) initialVec.clone();
		for(NodeDescriptor n : adding)
			total.add(n);
		leafSet.merge(adding);
		
		print("Before adjust"+leafSet);
		leafSet.adjustSuccPrec();
		print("After adjust:"+leafSet);
		
		assertEquals(LEAFSET_SIZE, leafSet.size());
		for(int i=0; i<leafSet.size(); i++){
			NodeDescriptor n = leafSet.get(i);
			if(found){
				nsucc++;
			}else{
				nprec++;
			}
			if(n.equals(localNodeDescriptor)){
				found = true;
			}
		}
		assertEquals(nsucc, nprec);
//		fail("Not yet implemented");
	}

	@Test
	public void testMerge(){
		print("Test Merge:");
		String names2[] = {"firstAdd", "secondAdd", "thirdAdd", "fourthAdd"};		
		Deque<NodeDescriptor> adding = new ArrayDeque<NodeDescriptor>(names2.length);
		Vector<NodeDescriptor> total = (Vector<NodeDescriptor>) initialVec.clone();
		for(String s : names2){
			NodeDescriptor n = new ConcreteNodeDescriptor(s);
			adding.add(n);
			total.add(n);
		}
		print("Leafset before adding:\n"+leafSet);
		leafSet.merge(adding);
		print("Leafset after adding:\n"+leafSet);
		
		//the adding vector is emptied
		assertEquals(0, adding.size());
		
		print("Verifying the augmented size...");
		print("totalSize: "+total.size()+
				" actualSize: "+leafSet.size());
		assertEquals(leafSet.size(), names2.length + LEAFSET_SIZE);
		print("ok");
		for(int i =0; i<leafSet.size(); i++){
			NodeDescriptor target = leafSet.get(i);
			if(!target.equals(ConcreteLeafSet.EMPTY))
				assertTrue(total.contains(target));
		}
//		fail("Not yet implemented");
	}
	
	private void print(Object o){
		System.out.println(o);
	}

}
